// 因为操作数据库最耗时的是连接数据库，所以对数据库进行封装，解决重复连接数据库问题
// 简单封装后存在多个实例化重复调用数据连接的问题，所以在封装时要解决。
const {MongoClient, ObjectId} = require('mongodb'); // 引入数据库
const config_db = require('./config'); // 引入db配置文件

/**
 * 封装db库
 */

class Db {
  // 创建一个静态方法，解决多个实例重复连接数据库的问题
  // 比如实例testDb1已经连接过数据库了，
  // 但是实例testDb2仍然会调用connect方法 去连接数据库，浪费了性能
  // 我们需要的是，当前面有实例连接过数据库时， 
  // 数据库处于连接状态，那么以后的实例都不需要再去连接了
  static getInstance() {
    if(!Db.instance) { // 如果不存在实例
      Db.instance = new Db(); // 就创建实例
    }
    return Db.instance;
  }
  constructor() {
    // 设置一个属性 解决某个实例上多个方法重复调用数据库连接的问题
    // 比如实例testDb已经连接过数据库了，那么在用find查询时，就不要再去重复连接了
    this.dbClient = ''; 

    this.connect(); // 初始化的时候就连接数据库
  }

  connect() { // 连接数据库
    return new Promise((resolve, reject) => {
      if(!this.dbClient) { // 如果dbClient不存在，就说明没调用过
        MongoClient.connect(config_db.dbUrl, (err, client) => {
          if(err) {
            reject(err);
          } else {
            this.dbClient = client.db(config_db.dbName);
            resolve(this.dbClient);
          }
        })
      } else { // 如果已经存在 说明被调用过了
        return resolve(this.dbClient);
      }
    })
  }

  add(collectionName, jsonData) { // 添加一条数据
    return new Promise((resolve, reject) => {
      this.connect()
      .then(db => {
        db.collection(collectionName)
        .insertOne(jsonData, (err, data) => {
          if(err) {
            reject(err);
          } else {
            resolve(data);
          }
        })
      })
      .catch(err => reject(err));
    })
  }

  addMany(collectionName, jsonArr) { // 添加多条数据
    return new Promise((resolve, reject) => {
      this.connect()
      .then(db => {
        db.collection(collectionName)
        .insertMany(jsonArr, (err, data) => {
          if(err) {
            reject(err);
          } else {
            resolve(data);
          }
        })
      })
      .catch(err => reject(err));
    })
  }

  /**删除 */
  delOne(collectionName, jsonData) {
    return new Promise((resolve, reject) => {
      this.connect()
        .then(db => {
          db.collection(collectionName)
            .deleteOne(jsonData, (err, data) => {
              if(err) {
                reject(err);
              }else {
                resolve(data);
              }
            })
        })
    })
  }

  delMany(collectionName, jsonData) {
    return new Promise((resolve, reject) => {
      this.connect()
        .then(db => {
          db.collection(collectionName)
            .deleteMany(jsonData, (err, data) => {
              if(err) {
                reject(err);
              }else {
                resolve(data);
              }
            })
        })
    })
  }

  // 更新一条数据
  update(collectionName, jsonData1, jsonData2) { 
    return new Promise((resolve, reject) => {
      this.connect()
      .then(db => {
        db.collection(collectionName)
        .updateOne(jsonData1,
          {
            $set: jsonData2,
          },
            (err, data) => {
          if(err) {
            reject(err);
          } else {
            resolve(data);
          }
        })
      })
    })
  }

  // 更新时删除一条数据
  update_delOne(collectionName, jsonData1, jsonData2) { 
    return new Promise((resolve, reject) => {
      this.connect()
      .then(db => {
        db.collection(collectionName)
        .updateOne(jsonData1,
          {
            $unset: jsonData2,
          },
            (err, data) => {
          if(err) {
            reject(err);
          } else {
            resolve(data);
          }
        })
      })
    })
  }

  /**
   * 当天第一次增加任务
   * 需要往task数组里增加对象
   * {
        date: new Date().getTime(),
        newTask: [],
        onGoing: [],
        finished: [],
        abandoned: []
      }
   */
  update_new_task(collectionName,jsonData1, jsonData2) {
    return new Promise((resolve, reject) => {
      this.connect()
        .then(db => {
          db.collection(collectionName)
          .updateOne(jsonData1, {
            $addToSet: {task: jsonData2}
          }, (err, data) => {
            if(err) {
              reject(err);
            } else {
              resolve(data);
            }
          })
        })
    })
  }

  // 更新嵌套数组内元素中某个字段的值
  update_$_data(collectionName, jsonData1, jsonData2) { 
    return new Promise((resolve, reject) => {
      this.connect()
        .then(db => {
          db.collection(collectionName)
            .updateOne(jsonData1, {
              $set: jsonData2
            }, (err, data) => {
              if(err) {
                reject(err);
              } else {
                resolve(data);
              }
            })
        })
    })
  }

  // 查找单个数据
  find(collectionName, jsonData) { 
    return new Promise((resolve, reject) => {
      this.connect()
      .then(db => {
        db.collection(collectionName).find(jsonData)
        .toArray((err, data) => {
          if(err) {
            reject(err);
          } else {
            resolve(data);
          }
        })
      })
      .catch(err => reject(err));
    })
  }

  // 获取_id，因为查询时用到的_id的值是ObjectId()类型的数据
  getObjectId(id) { 
    return new ObjectId(id);
  }

}

// const testDb = Db.getInstance();

// testDb.add('users', {hello: "world"})
// .then(data => console.log('添加成功', data));
// testDb.addMany('users', [{one: '第一条数据'}, {two: '第二条数据'}]);

// testDb.delOne('users', {one: "第一条数据"});
// testDb.delMany('users', {one: "第一条数据"});

// testDb.update('users', {one: "hello"}, {one: 'dilireba', age: 18})
// .then(data => console.log('更新成功', data));
// testDb.update_delOne('users', {two: 'world'}, {two: ''});

// testDb.find('users', {})
// .then(data => console.log('获取数据', data));

// testDb.update_new_task('users', {username: "222"}, 
// {
//   date: new Date().getTime(),
//   newTask: [],
//   onGoing: [],
//   finished: [],
//   abandoned: []
// })
// testDb.update_$_data('users', {username: "222", 'task.newTask': []}, {
//   'task.$.newTask': ['hello', 'world']
// })

module.exports = Db.getInstance();